package random;


import instrumentation.TrackerCoverage;



import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;



import GA.*;
import Operations.CreateObject;
import Operations.Operation;
import Operations.ValuesGenerator;
import util.*;

public class Launcher {
	protected static Logger logger = Logger.getLogger("Random Generator");	
	public static GAInfo     gaInfo     = new GAInfo();

	private static  TrackerCoverage track=  TrackerCoverage.getTracker();
	
    private static long startTime;
    private static long elapsed;
private static  long TestTimeout = 60 * 500; /* Timeout at 30 seconds */
//private static final long TestTimeout = 60 * 1000 * 15; /* Timeout at 60 seconds */

	public static long randomseed;// = (int) GAConfig.RANDOM_SEED;
	 public static int totalCoveredBranches=0;	
	 static int maximumBranchNumber=Integer.MAX_VALUE;
		
	public static  void run() throws ClassNotFoundException {
	//	String cut="toyexamples.Stack";
	//	String cut="database.Driver";
		try {
			System.out.println("CUT is:" + GAConfig.classFilePath);
			 Set<Class<?>> allClasses = new LinkedHashSet<Class<?>>();
		      //get class from file
		      allClasses.addAll(TestClusterBuilder.readClassFromFile());
		      if (!GAConfig.Silent) {
				System.out.println("There are " + allClasses.size()
						+ " classes as input");
				System.out.println(allClasses);
		      }
		      Set<Class<?>> classesToTest = TestClusterBuilder.filterUntestableClasses(allClasses);
		      if (!GAConfig.Silent){
		    	  System.out.println("There are " + classesToTest.size() + " classes to test after filtering");
		    	  System.out.println(classesToTest);
		      }	  
		    
			// calculate the test cluster and the set of types involved in the
				TestClusterBuilder TestCluster = new TestClusterBuilder(classesToTest);		
				 TestCluster.toString();

				gaInfo.setTestCluster(TestCluster);
				if (GAConfig.SaveData) 
					Log.log(gaInfo.getTestCluster().getClassToTest().toString());

			Map<String, Class<?>> cluster = TestCluster.getCluster();
			Map<String, String[]> refFactory = TestCluster.getRefFactory();
//			Map<String, ConstructorDeclared[]> classToTest = TestCluster.getClassToTest();

			startTime = Calendar.getInstance().getTimeInMillis();
			elapsed = Calendar.getInstance().getTimeInMillis() - startTime;
			gaInfo.setTestTimeOut(TestTimeout);
			gaInfo.setStartTime(startTime);
			int noMinutes=1;
			int it;
			for ( it = 0; (it <= 200000) && (elapsed < TestTimeout)&& gaInfo.getNoExecution()<=GAConfig.fitnessEvaluation; it++) {
			   	Map<String, List<CreateObject>> constructors= new LinkedHashMap <String, List<CreateObject>> ();
		    	List<Operation> ops = new LinkedList<Operation>();
//				System.out.println(it+ "----------------------");

		    	constructors=CreateObject.generateInitialClass(TestCluster);
				for (int i = 0; i < GAConfig.TestCaseRandomSize; i++)
					ops.add( Operation.randomlyGenerate(TestCluster));
			
				Chromosome chrom = new Chromosome(cluster,refFactory, constructors,ops);

//			System.out.println(it + " size:"+chrom.getSize());
//				System.out.println(it+ "----------------------");
				ReflectionExecutor.execute(gaInfo,chrom);
//				 track.calculateFitness(chrom);
	//			gaInfo.setNoExecution((gaInfo.getNoExecution()+1));
				totalCoveredBranches =track.getTotalCoveredBranch();
                elapsed = (Calendar.getInstance().getTimeInMillis() - startTime);
                if((it%100)==0 && it!=0 ){
                        System.out.print("elapsed time: "+ elapsed + " of "+TestTimeout);
                        System.out.println("\t Total Branch Covered= ( "+ totalCoveredBranches   +" ) and took "+ it +" iterations");
                }
    			if((elapsed/60000)==noMinutes){
	   				 if (GAConfig.SaveData) Log.log("At " +  noMinutes +" minute(s) Total Branch Covered= " + totalCoveredBranches );
	   				 noMinutes++;
    			}
    			if(totalCoveredBranches>=maximumBranchNumber)
    				break;

			}
			System.out.println("Maximum test time exceeded at "+ elapsed + " ms and took " + it + " iterations");
			System.out.println ("Maximum No of invocations " + gaInfo.getNoExecution());
	
			 if (GAConfig.SaveData) Log.log("Maximum test time exceeded at "+ elapsed + " ms and took " + it + " iterations");
			 if (GAConfig.SaveData) Log.log("Maximum No of invocations " + gaInfo.getNoExecution() );

			
			System.out.println(track.toString());
			if (GAConfig.SaveData) 
				Log.log(track.toString());
//			if (!GAConfig.Silent)
//					System.out.println(track.displayCondition());
			System.out.println(" ** Done Testing! **");
			if (GAConfig.SaveData)
				Log.log(" ** Done Testing! **");
			
		} catch (Exception e) {
			logger.log(Level.SEVERE, "Something went wrong: " + e.getMessage(), e);
		}
	}
	private static void experiment_configure_options(long TestTimeout,int j) {
		Log.log("Start testing #..."+j);
		Log.log ("      Seed              : "+randomseed);
			  
	}
public static void writeLogFile(int i ){
	String logFilePath = null;
	String fileName = new SimpleDateFormat("MM_dd_yyyy_hhmm'.txt'")
		.format(new Date());
	
String cName = GAConfig.classFilePath.substring(0,GAConfig.classFilePath.lastIndexOf("/") );
cName = cName.substring(cName.lastIndexOf("/") +1);
//cName=GAConfig.classFilePath;


logFilePath = "./logFiles/"+ cName+ "_RANDOM_"+i+  "_"+ fileName;
	
if (logFilePath != null) {
	Log.logConfig(logFilePath);
//	experiment_configure_options(TestTimeout);
	System.out.println("Log file place: "+ new File(logFilePath).getAbsolutePath());
	}
	Log.log("       SUT               : "+ GAConfig.classFilePath);
	Log.log ("      TestCase Size     : "+GAConfig.TestCaseRandomSize);
	Log.log ("      Timeout           : "+TestTimeout/60000 + " minutes  " + TestTimeout+" ms");
	Log.log ("");

}
public static void setTestTimeout(int i){
	if(i!=0)
	 TestTimeout = 60 * 1000*i;
	else
		 TestTimeout = 60 * 500;
		
	 
}
	public static void main(String[] args) {
		GAConfig.setAlgorithmName("Random Algorithm");
		if(args.length!=0){
			GAConfig.classFilePath=args[0];
			maximumBranchNumber=Integer.parseInt(args[1]);
		}

		for(int i=0;i<=0;i++){
		setTestTimeout(i);

		if (GAConfig.SaveData)
			writeLogFile(i);

	//	System.out.println("main Random Test");
		try {
		      for (int j = 1; j <= 5; j += 1) {
		    	  gaInfo     = new GAInfo();
		    	  System.out.println("Start testing #..."+j);
				//set the random generation seeds
		    	  randomseed=  System.currentTimeMillis();
				ValuesGenerator.resetSeed(randomseed);
				if (GAConfig.SaveData)
					experiment_configure_options(TestTimeout,j);
			
				run();
				
				track.setTrackerToNull();
			}
				if (GAConfig.SaveData)
					Log.log.close();
		} catch (Exception e) {
			logger.log(Level.SEVERE, "Something went wrong: " + e.getMessage(), e);			
		}

	}
//		System.exit(0);
	}

}
